﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace Kjs.Report.Infrastructure
{
    /// <summary>
    /// 统一ParameterExpression
    /// </summary>
    internal class ParameterReplacer : ExpressionVisitor
    {
        public ParameterReplacer(ParameterExpression paramExpr)
        {
            this.ParameterExpression = paramExpr;
        }

        public ParameterExpression ParameterExpression { get; private set; }

        public Expression Replace(Expression expr)
        {
            return this.Visit(expr);
        }

        protected override Expression VisitParameter(ParameterExpression p)
        {
            return this.ParameterExpression;
        }
    }

    public static class PredicateExtensions
    {
        public static Expression<Func<T, bool>> True<T>() { return f => true; }

        public static Expression<Func<T, bool>> False<T>() { return f => false; }

        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> exp_left, Expression<Func<T, bool>> exp_right)
        {
            var candidateExpr = Expression.Parameter(typeof(T), "candidate");
            var parameterReplacer = new ParameterReplacer(candidateExpr);

            var left = parameterReplacer.Replace(exp_left.Body);
            var right = parameterReplacer.Replace(exp_right.Body);
            var body = Expression.AndAlso(left, right);

            return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
        }

        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> exp_left, Expression<Func<T, bool>> exp_right)
        {
            var candidateExpr = Expression.Parameter(typeof(T), "candidate");
            var parameterReplacer = new ParameterReplacer(candidateExpr);

            var left = parameterReplacer.Replace(exp_left.Body);
            var right = parameterReplacer.Replace(exp_right.Body);
            var body = Expression.OrElse(left, right);

            return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
        }
    }

    //public static class Pagination
    //{
    //    private static readonly IDictionary<Type, object> fCache = new Dictionary<Type, object>();
    //    public static IEnumerable<T> Empty<T>()
    //    {
    //        var elemType = typeof(T);
    //        object temp;
    //        if (!fCache.TryGetValue(elemType, out temp))
    //        {
    //            var type = Type.GetType("Top.Data.PagedList`1, Top.Data").MakeGenericType(typeof(T));
    //            temp = Activator.CreateInstance(type, new List<T>(), 0);
    //            fCache[type] = temp;
    //        }
    //        return temp as IEnumerable<T>;
    //    }
    //}
}
